if ( typeof mix == 'undefined')
    mix = new Object();
    
function Renderer() {
    this._gl = null;
    this._frames = 0;
    this._viewMatrix = mat4.create();
    this._projMatrix = mat4.create();
    this._viewProjMatrix = mat4.create();
    this._isOrtho = false;
    this._autoView = true;
    this._clearColor = [0.0, 0.0, 0.0, 1.0];
    mix.renderer = this;
}

Renderer.prototype = {
init : function( canvas) {
    if ( !canvas.getContext) {
        console.warn( "Your browser can't support HTML5 Canvas.");
        return -1;
    }
    var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
    var gl = null;
    for ( var i = 0; i < names.length; ++i) {
        try {
            gl = canvas.getContext( names[i]);
        } catch( e) {}
        if ( gl)
            break;
    }
    if ( !gl ) {

        console.warn( "Your browser can't support WebGL.");
        return -1;
    }
    
    mix.gl = gl;
    this._gl = gl;
    this.setViewPort( 0, 0, canvas.width, canvas.height);
    with ( this) {
        gl.clearColor( _clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]);
    }
    gl.enable( gl.DEPTH_TEST);
    return 0;
},

setViewPort : function( x, y, width, height) {
    this._gl.viewPortX = x;
    this._gl.viewPortY = y;
    this._gl.viewPortW = width;
    this._gl.viewPortH = height;
    if ( this._isOrtho) {
        mat4.ortho( -width/2, -height/2, width/2, height/2, 0.1, 2800, this._projMatrix);
    } else {
        mat4.perspective( 45, width / height, 1.0, 2800, this._projMatrix);
    }
    if ( this._autoView) {
        var eyeZ = height * 1.2071067811865475;
        var focusX = width / 2.0;
        var focusY = -height / 2.0;
        mat4.lookAt( [focusX, focusY, eyeZ], [focusX, focusY, 0], [0, 1, 0], this._viewMatrix);
    }
    this._gl.viewport( x, y, width, height);
},

createBuffer : function( ar, fields, usage) {
    var gl = this._gl;
    var buffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, buffer);
    gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( ar), usage || gl.STATIC_DRAW);
    buffer.fields = fields;
    buffer.items = ar.length / fields;
    return buffer; 
},

createIndexBuffer : function( ar, fields, usage) {
    var gl = this._gl;
    var buffer = gl.createBuffer();
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffer);
    gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( ar), usage || gl.STATIC_DRAW);
    buffer.fields = fields;
    buffer.items = ar.length / fields;
    return buffer; 
},

uniformMatrix : function( u, m) {
    this._gl.uniformMatrix4fv( u.index, false, m);
},

uniformViewMatrix : function( u) {
    this.uniformMatrix( u, this._viewMatrix);
},

uniformProjMatrix : function( u) {
    this.uniformMatrix( u, this._projMatrix);
},

uniformViewProjMatrix : function( u) {
    var m = mat4.create();
    mat4.multiply( this._projMatrix, this._viewMatrix, m);
    this.uniformMatrix( u, m);
},

getViewProjMatrix : function( u) {
    mat4.multiply( this._projMatrix, this._viewMatrix, this._viewProjMatrix);
    return this._viewProjMatrix;
},

setBuffer : function( buffer, attrib) {
    var gl = this._gl;
    gl.bindBuffer( gl.ARRAY_BUFFER, buffer);
    if ( attrib) {
        if ( attrib.isArray)
            gl.vertexAttribPointer( attrib.index, buffer.fields, gl.FLOAT, false, 0, 0);
    }
},

setVertexBuffer : function( buffer, attrib) {
    this.setBuffer( buffer, attrib);
    this._curVertexBuf = buffer;
},

setIndexBuffer : function( buffer) {
    this._gl.bindBuffer( this._gl.ELEMENT_ARRAY_BUFFER, buffer);
    this._curIndexBuf = buffer;
},

setShader : function( shader) {
    this._gl.useProgram( shader._program);
    this._curShader = shader;
},

beginScene : function() {
    var gl = this._gl;
    //gl.viewport( gl.viewPortX, gl.viewPortY, gl.viewPortW, gl.viewPortH);
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    ++this._frames;
},

drawElements : function( indexBuf) {
    this.setIndexBuffer( indexBuf);
    var gl = this._gl;
    gl.drawElements( gl.TRIANGLES, indexBuf.items, gl.UNSIGNED_SHORT, 0);
},
};

